added some development tools
[windows-sources.git] / developer / Samples / NET 4.6 / Samples for Parallel / Raytracer / Raytracer_CSharp / Raytracer.cs
blob0a74274b7c5b645f627201dca771c29a2dcc3251
1 //--------------------------------------------------------------------------
2 //
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 //
5 // File: Raytracer.cs
6 //
7 //--------------------------------------------------------------------------
9 using System;
10 using System.Collections.Generic;
11 using System.Threading;
12 using System.Threading.Tasks;
14 namespace Microsoft.ParallelComputingPlatform.ParallelExtensions.Samples
16 internal sealed class RayTracer
18 private int screenWidth;
19 private int screenHeight;
20 private const int MaxDepth = 5;
22 public RayTracer(int screenWidth, int screenHeight)
24 this.screenWidth = screenWidth;
25 this.screenHeight = screenHeight;
28 internal void RenderSequential(Scene scene, Int32[] rgb)
30 for (int y = 0; y < screenHeight; y++)
32 int stride = y * screenWidth;
33 Camera camera = scene.Camera;
34 for (int x = 0; x < screenWidth; x++)
36 Color color = TraceRay(new Ray(camera.Pos, GetPoint(x, y, camera)), scene, 0);
37 rgb[x + stride] = color.ToInt32();
42 internal void RenderParallel(Scene scene, Int32[] rgb, ParallelOptions options)
44 Parallel.For(0, screenHeight, options, y =>
46 int stride = y * screenWidth;
47 Camera camera = scene.Camera;
48 for (int x = 0; x < screenWidth; x++)
50 Color color = TraceRay(new Ray(camera.Pos, GetPoint(x, y, camera)), scene, 0);
51 rgb[x + stride] = color.ToInt32();
53 });
56 internal void RenderParallelShowingThreads(Scene scene, Int32[] rgb, ParallelOptions options)
58 int id = 0;
59 Parallel.For<double>(0, screenHeight, options, () => GetHueShift(Interlocked.Increment(ref id)), (y, state, hue) =>
61 int stride = y * screenWidth;
62 Camera camera = scene.Camera;
63 for (int x = 0; x < screenWidth; x++)
65 Color color = TraceRay(new Ray(camera.Pos, GetPoint(x, y, camera)), scene, 0);
66 color.ChangeHue(hue);
67 rgb[x + stride] = color.ToInt32();
69 return hue;
70 },
71 hue => Interlocked.Decrement(ref id));
74 private Dictionary<int, double> _numToHueShiftLookup = new Dictionary<int, double>();
75 private Random _rand = new Random();
77 private double GetHueShift(int id)
79 double shift;
80 lock (_numToHueShiftLookup)
82 if (!_numToHueShiftLookup.TryGetValue(id, out shift))
84 shift = _rand.NextDouble();
85 _numToHueShiftLookup.Add(id, shift);
88 return shift;
91 internal readonly Scene DefaultScene = CreateDefaultScene();
93 static Scene CreateDefaultScene()
95 SceneObject[] things = {
96 new Sphere( new Vector(-0.5,1,1.5), 0.5, Surfaces.MatteShiny),
97 new Sphere( new Vector(0,1,-0.25), 1, Surfaces.Shiny),
98 new Plane( new Vector(0,1,0), 0, Surfaces.CheckerBoard)
100 Light[] lights = {
101 new Light(new Vector(-2,2.5,0),new Color(.5,.45,.41)),
102 new Light(new Vector(2,4.5,2), new Color(.99,.95,.8))
104 Camera camera = Camera.Create(new Vector(2.75, 2, 3.75), new Vector(-0.6, .5, 0));
106 return new Scene(things, lights, camera);
110 private ISect MinIntersection(Ray ray, Scene scene)
112 ISect min = ISect.Null;
113 foreach (SceneObject obj in scene.Things)
115 ISect isect = obj.Intersect(ray);
116 if (!ISect.IsNull(isect))
118 if (ISect.IsNull(min) || min.Dist > isect.Dist)
120 min = isect;
124 return min;
127 private double TestRay(Ray ray, Scene scene)
129 ISect isect = MinIntersection(ray, scene);
130 if (ISect.IsNull(isect))
131 return 0;
132 return isect.Dist;
135 private Color TraceRay(Ray ray, Scene scene, int depth)
137 ISect isect = MinIntersection(ray, scene);
138 if (ISect.IsNull(isect))
139 return Color.Background;
140 return Shade(isect, scene, depth);
143 private Color GetNaturalColor(SceneObject thing, Vector pos, Vector norm, Vector rd, Scene scene)
145 Color ret = new Color(0, 0, 0);
146 foreach (Light light in scene.Lights)
148 Vector ldis = Vector.Minus(light.Pos, pos);
149 Vector livec = Vector.Norm(ldis);
150 double neatIsect = TestRay(new Ray(pos, livec), scene);
151 bool isInShadow = !((neatIsect > Vector.Mag(ldis)) || (neatIsect == 0));
152 if (!isInShadow)
154 double illum = Vector.Dot(livec, norm);
155 Color lcolor = illum > 0 ? Color.Times(illum, light.Color) : new Color(0, 0, 0);
156 double specular = Vector.Dot(livec, Vector.Norm(rd));
157 Color scolor = specular > 0 ? Color.Times(Math.Pow(specular, thing.Surface.Roughness), light.Color) : new Color(0, 0, 0);
158 ret = Color.Plus(ret, Color.Plus(Color.Times(thing.Surface.Diffuse(pos), lcolor),
159 Color.Times(thing.Surface.Specular(pos), scolor)));
162 return ret;
165 private Color GetReflectionColor(SceneObject thing, Vector pos, Vector norm, Vector rd, Scene scene, int depth)
167 return Color.Times(thing.Surface.Reflect(pos), TraceRay(new Ray(pos, rd), scene, depth + 1));
170 private Color Shade(ISect isect, Scene scene, int depth)
172 Vector d = isect.Ray.Dir;
173 Vector pos = Vector.Plus(Vector.Times(isect.Dist, isect.Ray.Dir), isect.Ray.Start);
174 Vector normal = isect.Thing.Normal(pos);
175 Vector reflectDir = Vector.Minus(d, Vector.Times(2 * Vector.Dot(normal, d), normal));
176 Color ret = Color.DefaultColor;
177 ret = Color.Plus(ret, GetNaturalColor(isect.Thing, pos, normal, reflectDir, scene));
178 if (depth >= MaxDepth)
180 return Color.Plus(ret, new Color(.5, .5, .5));
182 return Color.Plus(ret, GetReflectionColor(isect.Thing, Vector.Plus(pos, Vector.Times(.001, reflectDir)), normal, reflectDir, scene, depth));
185 private double RecenterX(double x)
187 return (x - (screenWidth / 2.0)) / (2.0 * screenWidth);
189 private double RecenterY(double y)
191 return -(y - (screenHeight / 2.0)) / (2.0 * screenHeight);
194 private Vector GetPoint(double x, double y, Camera camera)
196 return Vector.Norm(Vector.Plus(camera.Forward, Vector.Plus(Vector.Times(RecenterX(x), camera.Right),
197 Vector.Times(RecenterY(y), camera.Up))));